package com.rc.saas.mini.common.push;

import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.http.MethodType;
import com.aliyuncs.http.ProtocolType;
import com.aliyuncs.profile.DefaultProfile;
import com.aliyuncs.profile.IClientProfile;
import com.aliyuncs.push.model.v20160801.PushRequest;
import com.aliyuncs.push.model.v20160801.PushResponse;
import com.aliyuncs.utils.ParameterHelper;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Date;

/**
 * 阿里云移动推送
 * https://help.aliyun.com/knowledge_detail/48089.html?spm=a2c4g.11186631.2.5.25e124e1iomTmA
 * Created by sven on 2019/5/17
 */
public class AliyunPushUtil {
    private final Logger logger = LoggerFactory.getLogger(AliyunPushUtil.class);

    private static DefaultAcsClient client;

    //#跟阿里云短信的一样
    private final String accessKeyId = "LTAI5t6a5w7ehL9zgggu3crj";
    private final String accessKeySecret = "qaOm7d0ryRksV4ZDJrwogyuffHMX1u";

    //333732927
//080248d2a98741cf9151c8e16405b042
    private final String iosAppKey = "333732927";
    private final String androidAppKey = "333732927";

    //目前该值固定，不用动
    private final String regionId = "cn-hangzhou";

    //static {
    //    IClientProfile profile = DefaultProfile.getProfile(regionId, accessKeyId, accessKeySecret);
    //    client = new DefaultAcsClient(profile);
    //}

    public AliyunPushUtil() {
        IClientProfile profile = DefaultProfile.getProfile(regionId, accessKeyId, accessKeySecret);
        client = new DefaultAcsClient(profile);
    }

    /**
     * 推送通知,会自动在手机端弹出通知栏，用户可以打开或者清除通知栏，通知通过ExtParameters发送数据
     * 参见文档 https://help.aliyun.com/document_detail/48089.html
     * @param account
     * @param body
     * @param extraData
     */
    public void pushNotice(String account, String body, String extraData) {
        if (StringUtils.isNotBlank(body)) {
            String defaultTitle = "通知";
            //String defaultTitle = "";
            pushIosNotic(account, defaultTitle, body, extraData, false);
            pushAndroidNotic(account, defaultTitle, body, extraData, false);
        }
    }

    /**
     * 推送通知,会自动在手机端弹出通知栏，用户可以打开或者清除通知栏，通知通过ExtParameters发送数据
     * 参见文档 https://help.aliyun.com/document_detail/48089.html
     * @param account
     * @param title
     * @param body
     * @param extraData
     */
    public void pushNotice(String account, String title, String body, String extraData) {
        if (StringUtils.isNotBlank(body)) {
            pushIosNotic(account, title, body, extraData, false);
            pushAndroidNotic(account, title, body, extraData, false);
        }
    }

    /**
     * 向所有用户推送通知,会自动在手机端弹出通知栏，用户可以打开或者清除通知栏，通知通过ExtParameters发送数据
     * 参见文档 https://help.aliyun.com/document_detail/48089.html
     * @param title
     * @param body
     * @param extraData
     */
    public void pushAllNotice(String title, String body, String extraData) {
        pushIosNotic(null, title, body, extraData, true);
        pushAndroidNotic(null, title, body, extraData, true);
    }

    /**
     * 推送消息,不会自动在通知栏弹出，只会在app中提示消息的接收,消息通过body发送数据
     * 透传消息，即自定义消息。只负责消息的推送，不做任何处理。客户端在接收到消息后，需要自己去处理消息的展示方式或后续动作
     * 参见文档 https://help.aliyun.com/document_detail/48089.html
     * @param account
     */
    public void pushMessage(String account, String body) {
        String defaultTitle = "消息";
        pushIosMessage(account, defaultTitle, body, false);
        pushAndroidMessage(account, defaultTitle, body, false);
    }

    /**
     * 推送消息,不会自动在通知栏弹出，只会在app中提示消息的接收,消息通过body发送数据
     * 透传消息，即自定义消息。只负责消息的推送，不做任何处理。客户端在接收到消息后，需要自己去处理消息的展示方式或后续动作
     * 参见文档 https://help.aliyun.com/document_detail/48089.html
     * @param account
     * @param title
     */
    public void pushMessage(String account, String title, String body) {
        pushIosMessage(account, title, body, false);
        pushAndroidMessage(account, title, body, false);
    }

    /**
     * 推送消息,不会自动在通知栏弹出，只会在app中提示消息的接收,消息通过body发送数据
     * 透传消息，即自定义消息。只负责消息的推送，不做任何处理。客户端在接收到消息后，需要自己去处理消息的展示方式或后续动作
     * 参见文档 https://help.aliyun.com/document_detail/48089.html
     * @param title
     */
    public void pushAllMessage(String title, String body) {
        pushIosMessage(null, title, body, true);
        pushAndroidMessage(null, title, body, true);
    }

    /**
     * IOS通知
     * @param account
     * @param title
     * @param body
     * @return
     */
    private boolean pushIosNotic(String account, String title, String body, String extraData, Boolean pushAll) {
        PushRequest pushRequest = new PushRequest();
        //安全性比较高的内容建议使用HTTPS
        pushRequest.setSysProtocol(ProtocolType.HTTPS);

        //内容较大的请求，使用POST请求
        pushRequest.setSysMethod(MethodType.POST);

        // 推送目标
        pushRequest.setAppKey(Long.valueOf(iosAppKey));

        //是否群发
        if (pushAll) {
            pushRequest.setTarget("ALL"); //推送目标: DEVICE:按设备推送 ALIAS : 按别名推送 ACCOUNT:按帐号推送  TAG:按标签推送; ALL: 广播推送
            pushRequest.setTargetValue("ALL"); //根据Target来设定，如Target=DEVICE, 则对应的值为 设备id1,设备id2. 多个值使用逗号分隔.(帐号与设备有一次最多100个的限制)
        } else {
            pushRequest.setTarget("ACCOUNT"); //推送目标: DEVICE:按设备推送 ALIAS : 按别名推送 ACCOUNT:按帐号推送  TAG:按标签推送; ALL: 广播推送
            pushRequest.setTargetValue(account); //根据Target来设定，如Target=DEVICE, 则对应的值为 设备id1,设备id2. 多个值使用逗号分隔.(帐号与设备有一次最多100个的限制)
        }

        pushRequest.setPushType("NOTICE"); // 消息类型 MESSAGE NOTICE
        pushRequest.setDeviceType("iOS"); // 设备类型 ANDROID iOS ALL.

        // 推送配置
        pushRequest.setTitle(title); // 消息的标题
        pushRequest.setBody(body); // 消息的内容

        // 推送配置: iOS
        pushRequest.setIOSBadge(1); // iOS应用图标右上角角标
        pushRequest.setIOSSilentNotification(false);//开启静默通知
        pushRequest.setIOSMusic("default"); // iOS通知声音
        //pushRequest.setIOSSubtitle("iOS10 subtitle");//iOS10通知副标题的内容
        pushRequest.setIOSNotificationCategory("iOS10 Notification Category");//指定iOS10通知Category
        pushRequest.setIOSMutableContent(true);//是否允许扩展iOS通知内容
        pushRequest.setIOSApnsEnv("PRODUCT");//iOS的通知是通过APNs中心来发送的，需要填写对应的环境信息。"DEV" : 表示开发环境 "PRODUCT" : 表示生产环境
        //pushRequest.setIOSRemind(true); // 消息推送时设备不在线（既与移动推送的服务端的长连接通道不通），则这条推送会做为通知，通过苹果的APNs通道送达一次。注意：离线消息转通知仅适用于生产环境
        //pushRequest.setIOSRemindBody("iOSRemindBody");//iOS消息转通知时使用的iOS通知内容，仅当iOSApnsEnv=PRODUCT && iOSRemind为true时有效
        pushRequest.setIOSExtParameters(extraData); //通知的扩展属性(注意 : 该参数要以json map的格式传入,否则会解析出错)

        // 推送控制
        //Date pushDate = new Date(System.currentTimeMillis()); // 30秒之间的时间点, 也可以设置成你指定固定时间
        //String pushTime = ParameterHelper.getISO8601Time(pushDate);
        //pushRequest.setPushTime(pushTime); // 延后推送。可选，如果不设置表示立即推送

        String expireTime = ParameterHelper.getISO8601Time(new Date(System.currentTimeMillis() + 12 * 3600 * 1000)); // 12小时后消息失效, 不会再发送
        pushRequest.setExpireTime(expireTime);
        pushRequest.setStoreOffline(true); // 离线消息是否保存,若保存, 在推送时候，用户即使不在线，下一次上线则会收到

        try {
            PushResponse pushResponse = client.getAcsResponse(pushRequest);

            if (pushResponse.getRequestId() != null && pushResponse.getMessageId() != null) {
                logger.info("iOS 发送成功 RequestId:{}, MessageID:{}", pushResponse.getRequestId(), pushResponse.getMessageId());
                return true;
            } else {
                return false;
            }
        } catch (Exception e) {
            logger.info("pushIosNotic 发送失败", e);
            return false;
        }
    }

    /**
     * ANDROID通知
     * @param account
     * @param title
     * @param body
     * @return
     */
    private boolean pushAndroidNotic(String account, String title, String body, String extraData, Boolean pushAll) {
        PushRequest pushRequest = new PushRequest();
        //安全性比较高的内容建议使用HTTPS
        pushRequest.setSysProtocol(ProtocolType.HTTPS);

        //内容较大的请求，使用POST请求
        pushRequest.setSysMethod(MethodType.POST);

        // 推送目标
        pushRequest.setAppKey(Long.valueOf(androidAppKey));

        //是否群发
        if (pushAll) {
            pushRequest.setTarget("ALL"); //推送目标: DEVICE:按设备推送 ALIAS : 按别名推送 ACCOUNT:按帐号推送  TAG:按标签推送; ALL: 广播推送
            pushRequest.setTargetValue("ALL"); //根据Target来设定，如Target=DEVICE, 则对应的值为 设备id1,设备id2. 多个值使用逗号分隔.(帐号与设备有一次最多100个的限制)
        } else {
            pushRequest.setTarget("ACCOUNT"); //推送目标: DEVICE:按设备推送 ALIAS : 按别名推送 ACCOUNT:按帐号推送  TAG:按标签推送; ALL: 广播推送
            pushRequest.setTargetValue(account); //根据Target来设定，如Target=DEVICE, 则对应的值为 设备id1,设备id2. 多个值使用逗号分隔.(帐号与设备有一次最多100个的限制)
        }

        pushRequest.setPushType("NOTICE"); // 消息类型 MESSAGE NOTICE
        pushRequest.setDeviceType("ANDROID"); // 设备类型 ANDROID iOS ALL.

        // 推送配置
        pushRequest.setTitle(title); // 消息的标题
        pushRequest.setBody(body); // 消息的内容

        // 推送配置: Android
        pushRequest.setAndroidNotifyType("SOUND");//通知的提醒方式 "VIBRATE" : 震动 "SOUND" : 声音 "BOTH" : 声音和震动 NONE : 静音
        pushRequest.setAndroidNotificationBarType(1);//通知栏自定义样式0-100
        pushRequest.setAndroidNotificationBarPriority(1);//通知栏自定义样式0-100
        //pushRequest.setAndroidNotificationChannel("1");
        pushRequest.setAndroidNotificationChannel("charge-pile");

        pushRequest.setAndroidOpenType("APPLICATION"); //点击通知后动作 "APPLICATION" : 打开应用 "ACTIVITY" : 打开AndroidActivity "URL" : 打开URL "NONE" : 无跳转
        //pushRequest.setAndroidOpenUrl("http://www.aliyun.com"); //Android收到推送后打开对应的url,仅当AndroidOpenType="URL"有效
        //pushRequest.setAndroidActivity("com.alibaba.push2.demo.XiaoMiPushActivity"); // 设定通知打开的activity，仅当AndroidOpenType="Activity"有效
        pushRequest.setAndroidMusic("default"); // Android通知音乐
        pushRequest.setAndroidXiaoMiActivity("com.ali.demo.MiActivity");//设置该参数后启动小米托管弹窗功能, 此处指定通知点击后跳转的Activity（托管弹窗的前提条件：1. 集成小米辅助通道；2. StoreOffline参数设为true）

        pushRequest.setAndroidXiaoMiNotifyTitle(title);
        pushRequest.setAndroidXiaoMiNotifyBody(body);
        pushRequest.setAndroidExtParameters(extraData); //设定通知的扩展属性。(注意 : 该参数要以 json map 的格式传入,否则会解析出错)

        // 推送控制
        //Date pushDate = new Date(System.currentTimeMillis()); // 30秒之间的时间点, 也可以设置成你指定固定时间
        //String pushTime = ParameterHelper.getISO8601Time(pushDate);
        //pushRequest.setPushTime(pushTime); // 延后推送。可选，如果不设置表示立即推送

        String expireTime = ParameterHelper.getISO8601Time(new Date(System.currentTimeMillis() + 12 * 3600 * 1000)); // 12小时后消息失效, 不会再发送
        pushRequest.setExpireTime(expireTime);
        pushRequest.setStoreOffline(true); // 离线消息是否保存,若保存, 在推送时候，用户即使不在线，下一次上线则会收到

        //设置的通知样式ID，通知栏自定义样式范围0-100(需要安卓端统一)
        pushRequest.setAndroidNotificationBarType(2);
        try {
            PushResponse pushResponse = client.getAcsResponse(pushRequest);

            if (pushResponse.getRequestId() != null && pushResponse.getMessageId() != null) {
                logger.info("Android 发送成功 RequestId:{}, MessageID:{}", pushResponse.getRequestId(), pushResponse.getMessageId());
                return true;
            } else {
                return false;
            }
        } catch (Exception e) {
            logger.info("pushAndroidNotic 发送失败", e);
            return false;
        }
    }

    /**
     * IOS 消息
     * @param account
     * @param title
     * @param body
     * @return
     */
    private boolean pushIosMessage(String account, String title, String body, Boolean pushAll) {
        PushRequest pushRequest = new PushRequest();
        //安全性比较高的内容建议使用HTTPS
        pushRequest.setSysProtocol(ProtocolType.HTTPS);

        //内容较大的请求，使用POST请求
        pushRequest.setSysMethod(MethodType.POST);

        // 推送目标
        pushRequest.setAppKey(Long.valueOf(iosAppKey));

        if (pushAll) {
            pushRequest.setTarget("ALL"); //推送目标: DEVICE:按设备推送 ALIAS : 按别名推送 ACCOUNT:按帐号推送  TAG:按标签推送; ALL: 广播推送
            pushRequest.setTargetValue("ALL"); //根据Target来设定，如Target=DEVICE, 则对应的值为 设备id1,设备id2. 多个值使用逗号分隔.(帐号与设备有一次最多100个的限制)
        } else {
            pushRequest.setTarget("ACCOUNT"); //推送目标: DEVICE:按设备推送 ALIAS : 按别名推送 ACCOUNT:按帐号推送  TAG:按标签推送; ALL: 广播推送
            pushRequest.setTargetValue(account); //根据Target来设定，如Target=DEVICE, 则对应的值为 设备id1,设备id2. 多个值使用逗号分隔.(帐号与设备有一次最多100个的限制)
        }

        pushRequest.setPushType("MESSAGE"); // 消息类型 MESSAGE NOTICE
        pushRequest.setDeviceType("iOS"); // 设备类型 ANDROID iOS ALL.

        // 推送配置
        pushRequest.setTitle(title); // 消息的标题
        pushRequest.setBody(body); // 消息的内容

        // 推送配置: iOS
        pushRequest.setIOSBadge(1); // iOS应用图标右上角角标
        pushRequest.setIOSSilentNotification(false);//开启静默通知
        pushRequest.setIOSMusic("default"); // iOS通知声音
        //pushRequest.setIOSSubtitle("iOS10 subtitle");//iOS10通知副标题的内容
        pushRequest.setIOSNotificationCategory("iOS10 Notification Category");//指定iOS10通知Category
        pushRequest.setIOSMutableContent(true);//是否允许扩展iOS通知内容
        pushRequest.setIOSApnsEnv("PRODUCT");//iOS的通知是通过APNs中心来发送的，需要填写对应的环境信息。"DEV" : 表示开发环境 "PRODUCT" : 表示生产环境
        //pushRequest.setIOSRemind(true); // 消息推送时设备不在线（既与移动推送的服务端的长连接通道不通），则这条推送会做为通知，通过苹果的APNs通道送达一次。注意：离线消息转通知仅适用于生产环境
        //pushRequest.setIOSRemindBody("iOSRemindBody");//iOS消息转通知时使用的iOS通知内容，仅当iOSApnsEnv=PRODUCT && iOSRemind为true时有效
        //pushRequest.setIOSExtParameters("{\"_ENV_\":\"DEV\",\"k2\":\"v2\"}"); //通知的扩展属性(注意 : 该参数要以json map的格式传入,否则会解析出错)

        // 推送控制
        //Date pushDate = new Date(System.currentTimeMillis()); // 30秒之间的时间点, 也可以设置成你指定固定时间
        //String pushTime = ParameterHelper.getISO8601Time(pushDate);
        //pushRequest.setPushTime(pushTime); // 延后推送。可选，如果不设置表示立即推送

        String expireTime = ParameterHelper.getISO8601Time(new Date(System.currentTimeMillis() + 12 * 3600 * 1000)); // 12小时后消息失效, 不会再发送
        pushRequest.setExpireTime(expireTime);
        pushRequest.setStoreOffline(true); // 离线消息是否保存,若保存, 在推送时候，用户即使不在线，下一次上线则会收到

        try {
            PushResponse pushResponse = client.getAcsResponse(pushRequest);

            if (pushResponse.getRequestId() != null && pushResponse.getMessageId() != null) {
                logger.info("iOS 发送成功 RequestId:{}, MessageID:{}", pushResponse.getRequestId(), pushResponse.getMessageId());
                return true;
            } else {
                return false;
            }
        } catch (Exception e) {
            logger.info("pushIosMessage 发送失败", e);
            return false;
        }
    }

    /**
     * ANDROID推送消息
     * @param account
     * @param title
     * @param body
     * @return
     */
    private boolean pushAndroidMessage(String account, String title, String body, Boolean pushAll) {
        PushRequest pushRequest = new PushRequest();
        //安全性比较高的内容建议使用HTTPS
        pushRequest.setSysProtocol(ProtocolType.HTTPS);

        //内容较大的请求，使用POST请求
        pushRequest.setSysMethod(MethodType.POST);

        // 推送目标
        pushRequest.setAppKey(Long.valueOf(androidAppKey));

        if (pushAll) {
            pushRequest.setTarget("ALL"); //推送目标: DEVICE:按设备推送 ALIAS : 按别名推送 ACCOUNT:按帐号推送  TAG:按标签推送; ALL: 广播推送
            pushRequest.setTargetValue("ALL"); //根据Target来设定，如Target=DEVICE, 则对应的值为 设备id1,设备id2. 多个值使用逗号分隔.(帐号与设备有一次最多100个的限制)
        } else {
            pushRequest.setTarget("ACCOUNT"); //推送目标: DEVICE:按设备推送 ALIAS : 按别名推送 ACCOUNT:按帐号推送  TAG:按标签推送; ALL: 广播推送
            pushRequest.setTargetValue(account); //根据Target来设定，如Target=DEVICE, 则对应的值为 设备id1,设备id2. 多个值使用逗号分隔.(帐号与设备有一次最多100个的限制)
        }

        pushRequest.setPushType("MESSAGE"); // 消息类型 MESSAGE NOTICE
        pushRequest.setDeviceType("ANDROID"); // 设备类型 ANDROID iOS ALL.

        // 推送配置
        pushRequest.setTitle(title); // 消息的标题
        pushRequest.setBody(body); // 消息的内容

        // 推送配置: Android
        pushRequest.setAndroidNotifyType("SOUND");//通知的提醒方式 "VIBRATE" : 震动 "SOUND" : 声音 "BOTH" : 声音和震动 NONE : 静音
        pushRequest.setAndroidNotificationBarType(1);//通知栏自定义样式0-100
        pushRequest.setAndroidNotificationBarPriority(1);//通知栏自定义样式0-100
        pushRequest.setAndroidNotificationChannel("1");

        pushRequest.setAndroidOpenType("APPLICATION"); //点击通知后动作 "APPLICATION" : 打开应用 "ACTIVITY" : 打开AndroidActivity "URL" : 打开URL "NONE" : 无跳转
        //pushRequest.setAndroidOpenUrl("http://www.aliyun.com"); //Android收到推送后打开对应的url,仅当AndroidOpenType="URL"有效
        //pushRequest.setAndroidActivity("com.alibaba.push2.demo.XiaoMiPushActivity"); // 设定通知打开的activity，仅当AndroidOpenType="Activity"有效
        pushRequest.setAndroidMusic("default"); // Android通知音乐
        pushRequest.setAndroidXiaoMiActivity("com.ali.demo.MiActivity");//设置该参数后启动小米托管弹窗功能, 此处指定通知点击后跳转的Activity（托管弹窗的前提条件：1. 集成小米辅助通道；2. StoreOffline参数设为true）

        pushRequest.setAndroidXiaoMiNotifyTitle(title);
        pushRequest.setAndroidXiaoMiNotifyBody(body);
        //pushRequest.setAndroidExtParameters("{\"k1\":\"android\",\"k2\":\"v2\"}"); //设定通知的扩展属性。(注意 : 该参数要以 json map 的格式传入,否则会解析出错)

        // 推送控制
        //Date pushDate = new Date(System.currentTimeMillis()); // 30秒之间的时间点, 也可以设置成你指定固定时间
        //String pushTime = ParameterHelper.getISO8601Time(pushDate);
        //pushRequest.setPushTime(pushTime); // 延后推送。可选，如果不设置表示立即推送

        String expireTime = ParameterHelper.getISO8601Time(new Date(System.currentTimeMillis() + 12 * 3600 * 1000)); // 12小时后消息失效, 不会再发送
        pushRequest.setExpireTime(expireTime);
        pushRequest.setStoreOffline(true); // 离线消息是否保存,若保存, 在推送时候，用户即使不在线，下一次上线则会收到

        try {
            PushResponse pushResponse = client.getAcsResponse(pushRequest);

            if (pushResponse.getRequestId() != null && pushResponse.getMessageId() != null) {
                logger.info("Android 发送成功 RequestId:{}, MessageID:{}", pushResponse.getRequestId(), pushResponse.getMessageId());
                return true;
            } else {
                return false;
            }
        } catch (Exception e) {
            logger.info("pushAndroidMessage 发送失败", e);
            return false;
        }
    }
}
